/**
 * @author casazaft
 */
Package("xclab.mvc.patterns.observer").Class("Notification",{
	Notification:function(name, body, type){
	        
        this.name = name;
        this.body = body;
        this.type = type;
    },
    Prototype: {
        getName: function(){
            return this.name;
        },
        getBody: function(){
            return this.body;
        },
        getType: function(){
            return this.type;
        },
        setBody: function(body){
            this.body = body;
        },
        setType: function(type){
            this.type = type;
        }
    }
});


Package("xclab.mvc.patterns.observer").Class("Notifier",{
	Notifier:function(){
	        
        this.facade = xclab.mvc.patterns.facade.Facade.getInstance();
    },
    Prototype: {
        sendNotification: function(name, body, type){
            this.facade.sendNotification(name, body, type);
        }
    }
});


Package("xclab.mvc.patterns.observer").Class("Observer",{
	Observer:function(notifyMethod, notifyContext){
	        
        this.setNotifyMethod(notifyMethod);
        this.setNotifyContext(notifyContext);
        
    },
    Prototype: {
        setNotifyMethod: function(notifyMethod){
            this.notify = notifyMethod;
        },
        setNotifyContext: function(notifyContext){
            this.context = notifyContext;
        },
        getNotifyMethod: function(){
            return this.notify;
        },
        getNotifyContext: function(){
            return this.context;
        },
        notifyObserver: function(notification){
            var method = this.notify;
            var context = this.context;
            method.apply(context, [notification]);
        },
        compareNotifyContext: function(p_context){
            return this.getNotifyContext() == p_context;
        }
    }
});


Package("xclab.mvc.patterns.command").Class("MacroCommand",{
	MacroCommand:function(){
	        this.subCommands = [];
        this.initializeMacroCommand();
    },
    Prototype: {
        addSubCommand: function(commandClassRef){
            this.subCommands.push(commandClassRef);
            
        },
        execute: function(notification){
            while (this.subCommands.length > 0) {
                var commandClassRef = this.subCommands.shift();
                var commandInstance = new commandClassRef();
                commandInstance.execute(notification);
            }
        }
        
    },
    Extends: xclab.mvc.patterns.observer.Notifier
});


Package("xclab.mvc.patterns.command").Class("SimpleCommand",{
	SimpleCommand:function(){
	    },
    Prototype: {
        execute: function(){
        
        }
    },
    Extends: xclab.mvc.patterns.observer.Notifier
});


Package("xclab.mvc.patterns.mediator").Class("Mediator",{
	Mediator:function(name, viewComponent){
	        
        if (typeof name == 'object') {
            viewComponent = name;
            name = this.getClass().getName();
        }
        this.mediatorName = name;
        this.viewComponent = viewComponent;
    },
    Prototype: {
        getMediatorName: function(){
            return this.mediatorName;
        },
        setViewComponent: function(viewComponent){
            this.viewComponent = viewComponent;
        },
        getViewComponent: function(){
            return this.viewComponent;
        },
        listNotificationInterests: function(){
            return [];
        },
        handleNotification: function(notification){
        
        },
        onRegister: function(){
        
        },
        onRemove: function(){
        
        }
    },
    Extends: xclab.mvc.patterns.observer.Notifier
});


Package("xclab.mvc.patterns.proxy").Class("Proxy",{
	Proxy:function(name, data){
	        
        this.proxyName = (name != null) ? name : this.getClass().getName();
        if (data) 
            this.setData(data);
    },
    Prototype: {
        getProxyName: function(){
            return this.proxyName;
        },
        setData: function(data){
            this.data = data;
        },
        getData: function(){
            return this.data;
        },
        onRegister: function(){
        
        },
        onRemove: function(){
        
        }
    },
    Extends: xclab.mvc.patterns.observer.Notifier
});


/**
 * @author casazaft
 */
Package("xclab.mvc.core").Class("View",{
	View:function(){
	        
        ;
        this.mediatorMap = {};
        this.observerMap = {};
        this.initializeView();
    },
    Prototype: {
        initializeView: function(){
        
        },
        registerObserver: function(noteName, observer){
            var observers = this.observerMap[noteName];
            
            if (observers) {
                observers.push(observer);
            }
            else {
                this.observerMap[noteName] = [observer];
                
            }
        },
        notifyObservers: function(note){
        
            if (this.observerMap[note.getName()]) {
            
                var observersRef = this.observerMap[note.getName()];
                
                var observers = [];
                var observer = null;
                for (var i = 0; i < observersRef.length; i++) {
                    observer = observersRef[i];
                    observers.push(observer);
                }
                
                for (var i = 0; i < observers.length; i++) {
                    observer = observers[i];
                    observer.notifyObserver(note);
                }
            }
        },
        removeObserver: function(noteName, noteContext){
            var observers = this.observerMap[noteName];
            var observeClass = null;
            for (var i = 0; i < observers.length; i++) {
                observeClass = observers[i];
                if (observeClass.compareNotifyContext(noteContext) == true) {
                    observers.splice(i, 1);
                    break;
                    
                    
                }
            }
            if (observers.length == 0) {
                delete this.observerMap[noteName];
            }
        },
        registerMediator: function(mediator){
            var Observer = Import("xclab.mvc.patterns.observer.Observer");
            if (this.mediatorMap[mediator.getMediatorName()]) 
                return;
            this.mediatorMap[mediator.getMediatorName()] = mediator;
            var interests = mediator.listNotificationInterests();
            if (interests.length > 0) {
                var observer = null;
                for (var i = 0; i < interests.length; i++) {
                    observer = new Observer(mediator.handleNotification, mediator);
                    this.registerObserver(interests[i], observer);
                }
            }
            mediator.onRegister();
        },
        retrieveMediator: function(mediatorName){
            return this.mediatorMap[mediatorName];
        },
        removeMediator: function(mediatorName){
            var mediator = this.mediatorMap[mediatorName];
            if (mediator) {
                var interests = mediator.listNotificationInterests();
                for (var i = 0; i < interests.length; i++) {
                    this.removeObserver(interests[i], mediator);
                }
                delete this.mediatorMap[mediatorName];
                mediator.onRemove();
            }
            return mediator;
        },
        hasMediator: function(mediatorName){
            return this.mediatorMap.hasOwnProperty(mediatorName);
        }
        
        
    },
    Extends: j2j.patterns.Singleton
});


Package("xclab.mvc.core").Class("Controller",{
	Controller:function(){
	        
        ;
        this.commandMap = {};
        this.initializeController();
    },
    Prototype: {
        initializeController: function(){
            var View = Import("xclab.mvc.core.View");
            this.view = View.getInstance();
            
        },
        executeCommand: function(note){
        
            var commandClassRef = this.commandMap[note.getName()];
            
            if (!commandClassRef) 
                return;
            var commandInstance = new commandClassRef();
            commandInstance.execute(note);
        },
        registerCommand: function(noteName, commandClassRef){
            var Observer = Import("xclab.mvc.patterns.observer.Observer");
            if (!this.commandMap[noteName]) {
                this.view.registerObserver(noteName, new Observer(this.executeCommand, this));
            }
            this.commandMap[noteName] = commandClassRef;
        },
        hasCommand: function(noteName){
            return this.commandMap.hasOwnProperty(noteName);
        },
        removeCommand: function(noteName){
            if (this.hasCommand(noteName)) {
                this.view.removeObserver(noteName, this);
                delete this.commandMap[noteName];
            }
        }
    },
    Extends: j2j.patterns.Singleton
});


Package("xclab.mvc.core").Class("Model",{
	Model:function(){
	        
        ;
        this.proxyMap = [];
        this.initializeModel();
    },
    Prototype: {
        initializeModel: function(){
        
        },
        registerProxy: function(proxy){
            this.proxyMap[proxy.getProxyName()] = proxy;
            proxy.onRegister();
        },
        retrieveProxy: function(proxyName){
            return this.proxyMap[proxyName];
        },
        hasProxy: function(proxyName){
            return this.proxyMap.hasOwnProperty(proxyName);
        },
        removeProxy: function(proxyName){
            var proxy = this.proxyMap[proxyName];
            if (proxy) {
                delete this.proxyMap[proxyName];
                proxy.onRemove();
            }
            return proxy;
        }
    },
    Extends: j2j.patterns.Singleton
});



/**
 * @author casazaft
 */
Package("xclab.mvc.patterns.facade").Class("Facade",{
	Facade:function(){
	        this.controller = null;
        this.view = null;
        this.model = null;
        this.initializeFacade();
    },
    Prototype: {
        initializeFacade: function(){
            this.initializeModel();
            this.initializeController();
            this.initializeView();
            
        },
        initializeModel: function(){
            if (this.model != null) 
                return;
            
            var Model = Import("xclab.mvc.core.Model");
            this.model = Model.getInstance();
        },
        initializeController: function(){
            if (this.controller != null) 
                return;
            var Controller = Import("xclab.mvc.core.Controller");
            
            this.controller = Controller.getInstance();
        },
        initializeView: function(){
            if (this.view != null) 
                return;
            var View = Import("xclab.mvc.core.View");
            this.view = View.getInstance();
        },
        registerCommand: function(notificationName, commandClassRef){
        
            this.controller.registerCommand(notificationName, commandClassRef);
        },
        removeCommand: function(notificationName){
            return this.controller.removeCommand(notificationName);
        },
        hasCommand: function(notificationName){
            return this.controller.hasCommand(notificationName);
        },
        registerProxy: function(proxy){
            this.model.registerProxy(proxy);
        },
        retrieveProxy: function(proxy){
            return this.model.retrieveProxy(proxy);
        },
        removeProxy: function(proxy){
            return this.model.removeProxy(proxy);
        },
        hasProxy: function(proxy){
            return this.model.hasProxy(proxy);
        },
        registerMediator: function(mediator){
            this.view.registerMediator(mediator);
        },
        retrieveMediator: function(mediator){
            return this.view.retrieveMediator(mediator);
        },
        removeMediator: function(mediator){
            return this.view.removeMeidator(mediator);
        },
        hasMediator: function(mediator){
            return this.view.hasMediator(mediator);
        },
        notifyObservers: function(notification){
            if (this.view != null) {
                this.view.notifyObservers(notification);
                
            }
        },
        sendNotification: function(name, body, type){
            var Notification = Import("xclab.mvc.patterns.observer.Notification");
            this.notifyObservers(new Notification(name, body, type));
        }
        
        
    },
    Extends: j2j.patterns.Singleton
});




